
#include "header.h"

void PrintTabs(int count);

// --------------------------------------------------------
// LoadDataFile()
//		This method will load the data file from disk.
int CDataFile::LoadDataFile(char *filename, int flags)
{
	FILE		*fp;						// File pointer to data file
	char		curLine[MAX_LINE_LENGTH];	// the current line being processed
	
	DataCollection	*pCurrent;		// A pointer to the current collection we are 
									// loading entries into.

	// Initialize the data collection before loading this data file into in
	if(Initialize() == EXIT_FAILURE)
	{
		printf("Error calling the Initialize Method\n");
		return 0;
	}

	// To begin, set the Cur object pointer to the root object
	pCurrent = pRoot;


	// First make sure the file does in fact exist and can be opened.
	if((fp = fopen(filename, "r")) == NULL)
	{	// Can't open the data file to read.
		printf("Error opening file...\n");
		return ERR_CANNOT_OPEN_FILE;
	}
	
	
	// fgets will return NULL at EOF, so check for that.
	while(fgets(curLine, MAX_LINE_LENGTH, fp) != NULL)		
	{
		bool bProcessLine = true;
		char buffer[80];			// buffer for getting strings out of the line
		
		// Remove all spaces from the line
		// This makes it easier to process the line.
		RemoveSpaces(curLine, 0);
			
		while(bProcessLine)
		{
			// check the line for 1 of the following: '=', '{', or '}'
			for(int i = 0; i < (int)strlen(curLine); i++)
			{	
				// Check for a comment line first and end processing this line if found
				if((curLine[i] == '/') && (curLine[i+1] == '/'))
				{
					bProcessLine = false;
					break;
				}

				//copy each character to the buffer
				buffer[i] = curLine[i];   // This will get the Name of the property or collection
				
				// If current line has an '=' this means this is an entry and not
				// a collection
				if(curLine[i] == '=')
				{
					// This is an entry for the current object.
					DataEntry		*entry;

					// cap off the buffer (this removes the '=' sign from the name.
					buffer[i] = '\0';

					
					// Allocate memory to hold data
					entry = (DataEntry *)malloc(sizeof(DataEntry));
					if(!entry)
					{
						printf("Error making property.\n");
					}
					// initialize the new property structure
					entry->pName = NULL;
					entry->pValue = NULL;
					entry->pNext = NULL;
					entry->pPrev = NULL;

					// Everything before the '=' is the property name,
					// and everything after it is the value.
					entry->pName = (char *)malloc(i + 1);
					if(entry->pName == NULL)
					{
						printf("Error allocting space for name\n");
					}
					strcpy(entry->pName, buffer);
										
					// Everything after the '=' will be the value...
					entry->pValue = (char *)malloc(strlen(curLine) - i);
					if(entry->pValue == NULL)
					{
						printf("Error allocting space for Value\n");
					}
					strcpy(entry->pValue, &curLine[i + 1]);
					if(entry->pValue[strlen(entry->pValue)- 2] == ';')
						entry->pValue[strlen(entry->pValue)- 2 ] = '\0';
					
					// Ok, have the name and value pair, now time 
					// to add it to the current object
					
					DataEntry	*iter;					
					
					iter = pCurrent->pHeadEntry;
					if(iter == NULL)
					{
						pCurrent->pHeadEntry = entry;
					} else {
						// Cycle through until the last entry
						while(iter->pNext != NULL)
						{
							iter = iter->pNext;
						}					
						iter->pNext = entry;
						entry->pNext = NULL;
						entry->pPrev = iter;
					}
					pCurrent->numOfEntries++;
				} // if(curLine[i] == '=')

				// If this is the start of a new Collection
				if(curLine[i] == '{')
				{
					// Need to create a new object now...
					DataCollection *pNewCollection;
									
					// Allocate space for new object
					pNewCollection = (DataCollection *)malloc(sizeof(DataCollection));
					memset(pNewCollection, 0, sizeof(DataCollection));
					
					// Get the name of this new collection and set it to the 
					// current collection for processing
					buffer[i] = '\0';
					
					pNewCollection->sName = (char *)malloc(strlen(buffer));
					strcpy(pNewCollection->sName, buffer);

					// Set the parent for this new collection.
					pNewCollection->pParentCollection = pCurrent;
					
					// Add this collection to the current collection list.
					if(pCurrent->pHeadCollection == NULL)
					{
						pCurrent->pHeadCollection = pNewCollection;
						pNewCollection->pNext = NULL;
						pNewCollection->pPrev = NULL;
					} else
					{
						DataCollection *iter = pCurrent->pHeadCollection;
						while(iter->pNext != NULL)
						{
							iter = iter->pNext;
						}
						iter->pNext = pNewCollection;
						pNewCollection->pNext = NULL;
						pNewCollection->pPrev = iter;
					}
					pCurrent->numOfCollections++;					
					pCurrent = pNewCollection;
										
				} // if(curLine[i] == '{')

				if(curLine[i] == '}')
				{
					// Done with this object, go back to parent object now
					if(pCurrent->pParentCollection != NULL)
						pCurrent = pCurrent->pParentCollection;
				}
			}
			bProcessLine = false;
			//printf("TempBuf: %s\n", tempBuf);

		} // while(bProcessLine)
	} // while(fgets(buffer, MAX_LINE_LENGTH, fp) != NULL)

	// Close the file now the it is loaded.
	if(fp)
		fclose(fp);

	return EXIT_SUCCESS;
} // int CDataFile::LoadDataFile(char *filename, int flags)



int CDataFile::UnloadDataFile(void)
{
	DataCollection		*currentDC, *iterDC;
	DataEntry			*currentE, *iterE;

	currentDC = pRoot;
	
	// Go through all the collections and free the memory associated with them
	while(currentDC)
	{
		// Free all entries first
		iterE = currentDC->pHeadEntry;
		while(iterE != NULL)
		{
			printf("Unloading: %s\n", iterE->pName);
			free(iterE->pName);
			free(iterE->pValue);
			iterE->type = NULL;
			iterE->pPrev = NULL;

			iterE = iterE->pNext;
		}
		if(currentDC->pNext)
		{
			currentDC = currentDC->pNext;
		} else {
			currentDC = currentDC->pHeadCollection;
		}
	} // while(currentDC)

	return EXIT_SUCCESS;
}



int CDataFile::PrintCollection(void)
{
	DataCollection		*pCurrentCollection;
	DataEntry			*pCurrentEntry;
	int					nestCount = 0;	// Count of how deep in a nested collection
										// we are (used for tabs when printing)

	// Go through each collection starting with the root collection
	// List the entries first, followed by the next object.

	pCurrentCollection = pRoot;
	
	// Cycle throught the collections found within the root collection
	// Start with sibling collections, then move to the child collections.
	while(pCurrentCollection)
	{
		// Print name of collection
		printf("\n");
		PrintTabs(nestCount);
		printf("Collection: %s\n", pCurrentCollection->sName);
		// Cycle through the entries of this collection
		pCurrentEntry = pCurrentCollection->pHeadEntry;
		while(pCurrentEntry)
		{
			PrintTabs(nestCount + 1);
			printf("%s:\t\t%s\n", pCurrentEntry->pName, pCurrentEntry->pValue);
			pCurrentEntry = pCurrentEntry->pNext;
		}

		// Check for more sibling collections, if none then start with
		// the children of this collection
		if(pCurrentCollection->pNext == NULL)
		{
			pCurrentCollection = pCurrentCollection->pHeadCollection;
			nestCount++; // Increase this count when going down the line
		} else
			pCurrentCollection = pCurrentCollection->pNext;		
	} // while(pCurrentCollection)

	return EXIT_SUCCESS;
} // int CDataFile::PrintCollection(void)


// --------------------------------------------------------
// Constructor Method
//
// Initialise the pRoot member of the class.
// --------------------------------------------------------
CDataFile::CDataFile()
{
	// Set member to NULL to avoid any errors with the code.
	pRoot = NULL;
}

CDataFile::~CDataFile()
{

}


int CDataFile::Initialize(void)
{
	// Only initialize if pDataObject == NULL.  If this does not
	// == NULL that means this is already initialized with data.
	if(pRoot == NULL)
	{
		pRoot = (DataCollection *)malloc(sizeof(DataCollection));
		if(pRoot == NULL)
		{
			printf("Could not allocate the data object.....");
			return EXIT_FAILURE;
		}

		// Now clear out the data members
		ClearData(this->pRoot);

		pRoot->sName = (char *)malloc(sizeof("Root") + 1);
		if(pRoot->sName == NULL)
		{
			printf("Error setting root object name");
			return EXIT_FAILURE;
		}
		strcpy(pRoot->sName, "Root");

	} // if(pDataObject == NULL)

	return EXIT_SUCCESS;
} // int CDataFile::Initialize(void)



// --------------------------------------------------------
// void ClearData(DataObject *data)
//
// This method will clear out the member variables
// of the given DataObject. 
// --------------------------------------------------------
void CDataFile::ClearData(DataCollection *data)
{
	// Only need to clear out the data if it is 
	// allocated, else just skip this clearing.
	if(data != NULL)
	{
		// Clear the dataobject to initial values of 0
		data->sName				= NULL;
		data->pParentCollection	= NULL;
		data->numOfCollections	= 0;
		data->numOfEntries		= 0;
		data->pHeadCollection	= NULL;
		data->pHeadEntry		= NULL;
		data->pNext				= NULL;
		data->pPrev				= NULL;
	} // if(data != NULL)
} //void CDataFile::ClearData(DataObject *data)


int CDataFile::GetInt(char *Collection, char *Entry)
{
	DataCollection *current;
	DataEntry		*entry, *iter;

	// Set the current collection to be root
	current = pRoot;
	
	// Check all entries within the current collection
	// Cycle through the sibling collections
	// go through children collections.
	while(current)
	{
		if((strcmp(current->sName, Collection)) == 0)
		{
			//found our collection
			// Cycle through the entries
			iter = current->pHeadEntry;
			while(iter)
			{
				if((strcmp(iter->pName, Entry)) == 0)
				{
					// Found our entry.
					// Make sure the data type is an int
				/*	if(iter->type != ENTRY_INT)
					{
						// Not an int, cannot return value
						return NULL;
					}*/
					return atoi(iter->pValue);
				} // if((strcmp(iter->pName, Entry)) == 0)

				iter = iter->pNext;
			} // while(iter)
		} // if((strcmp(current->sName, Collection)) == 0)

		// No go, wrong collection
		if(current->pNext == NULL)
		{	
			current = current->pHeadCollection;
		}
		else {
			current = current->pNext; 
		}
	} // while(current)

	return NULL;
}

float GetFloat(char *Collection, char *Entry)
{

	return NULL;
}
char * CDataFile::GetString(char *Collection, char *Entry)
{
	DataCollection *current;
	DataEntry		*entry, *iter;

	// Set the current collection to be root
	current = pRoot;
	
	// Check all entries within the current collection
	// Cycle through the sibling collections
	// go through children collections.
	while(current)
	{
		if((strcmp(current->sName, Collection)) == 0)
		{
			//found our collection
			// Cycle through the entries
			iter = current->pHeadEntry;
			while(iter)
			{
				if((strcmp(iter->pName, Entry)) == 0)
				{
					// Found our entry.
					// Make sure the data type is an int
				/*	if(iter->type != ENTRY_INT)
					{
						// Not an int, cannot return value
						return NULL;
					}*/
					return iter->pValue;
				} // if((strcmp(iter->pName, Entry)) == 0)

				iter = iter->pNext;
			} // while(iter)
		} // if((strcmp(current->sName, Collection)) == 0)

		// No go, wrong collection
		if(current->pNext == NULL)
		{	
			current = current->pHeadCollection;
		}
		else {
			current = current->pNext; 
		}
	} // while(current)

	return NULL;
}








void PrintTabs(int count)
{
	for(int i = 0; i < count; i++)
		printf("\t");
}